#include "./../../Headers/mathematics/math_def.h"

namespace Mathematics {

	Comparison cmp;
	
#ifdef USING_STL_CONTAINERS
	vector<uint> fat_list;

	uint Fat( const usint &param ){
		if( fat_list.empty() ){
			fat_list.push_back( 1 );
		}
		while( param >= fat_list.size() ){
			fat_list.push_back( fat_list.back() * fat_list.size() );
			if( fat_list.back() < fat_list[ fat_list.size()-2 ] ){
				cout << "Parameter is too big for Fatorial: " << fat_list.size()-1 << eendl;
				fat_list.pop_back();
				return 0;
			}
		}
		return fat_list[param];
	};

	vector<uint> fib_list;

	uint Fib( const usint &param ){
		if( fib_list.empty() ){
			fib_list.push_back( 1 );
			fib_list.push_back( 1 );
		}
		while( param >= fib_list.size() ){
			fib_list.push_back( fib_list.back() + fib_list[ fib_list.size()-2 ] );
			if( fib_list.back() < fib_list[ fib_list.size()-2 ] ){
				cout << "Parameter is too big for Fibonacci: " << fib_list.size()-1 << eendl;
				fib_list.pop_back();
				return 0;
			}
		}
		return fib_list[param];
	};

#else // not USING_STL_CONTAINERS
	uint Fat( const usint &param ){
		if( param < 2 ){
			return 1;
		}
		return param * Fatorial(param-1);
	};

	uint Fib( const usint &param ){
		if( param < 2 ){
			return 1;
		}
		return Fib( param-1 ) + Fib( param-2 );
		/*// non recursive fibonacci
		const double r5 = sqrt( 5.0 );
		const int n_1 = param + 1;
		return Round(
			( pow( (1 + r5)/2.0 , n_1 ) - pow( (1 - r5)/2.0 , n_1 ) ) / r5
		);
		*/
	};

#endif // USING_STL_CONTAINERS

	//! function for testing mathematical default definitions
	void MathTest(){
		
		cout << endl << "---MathTest---" << endl;
		
		cout << "Max(1.0,2.0) = " << Max(1.0,2.0) << endl;
		cout << "Max('a','b') = " << Max('a','b') << endl;
		cout << "Min(1.0,2.0) = " << Min(1.0,2.0) << endl;
		cout << "Signal(2.5) = " << Signal(2.5) << endl;
		cout << "Signal(-2.5) = " << Signal(-2.5) << endl;
		cout << "Signal(0.0) = " << Signal(0.0) << endl;
		cout << "Mod(2.5) = " << Mod(2.5) << endl;
		cout << "Mod(-2.5) = " << Mod(-2.5) << endl;
		cout << "Alias -> Abs(-2.5) = " << Abs(-2.5) << endl;
		cout << "Round(2.1) = " << Round(2.1) << endl;
		cout << "Round(-2.1) = " << Round(-2.1) << endl;
		cout << "Round(2.9) = " << Round(2.9) << endl;
		cout << "Round(-2.9) = " << Round(-2.9) << endl;
		cout << "Fract(2.1) = " << Fract(2.1) << endl;
		cout << "Fract(-2.1) = " << Fract(-2.1) << endl;
		cout << "Fract(2.9) = " << Fract(2.9) << endl;
		cout << "Fract(-2.9) = " << Fract(-2.9) << endl;
		cout << "Low(2.1) = " << Low(2.1) << endl;
		cout << "Low(-2.1) = " << Low(-2.1) << endl;
		cout << "Low(2.9) = " << Low(2.9) << endl;
		cout << "Low(-2.9) = " << Low(-2.9) << endl;
		cout << "Upp(2.1) = " << Upp(2.1) << endl;
		cout << "Upp(-2.1) = " << Upp(-2.1) << endl;
		cout << "Upp(2.9) = " << Upp(2.9) << endl;
		cout << "Upp(-2.9) = " << Upp(-2.9) << endl;
		cout << "Near(2.1) = " << Near(2.1) << endl;
		cout << "Near(-2.1) = " << Near(-2.1) << endl;
		cout << "Near(2.9) = " << Near(2.9) << endl;
		cout << "Near(-2.9) = " << Near(-2.9) << endl;
		cout << "Far(2.1) = " << Far(2.1) << endl;
		cout << "Far(-2.1) = " << Far(-2.1) << endl;
		cout << "Far(2.9) = " << Far(2.9) << endl;
		cout << "Far(-2.9) = " << Far(-2.9) << endl;
		cout << "Fat(0) = " << Fat(0) << endl;
		cout << "Fat(1) = " << Fat(1) << endl;
		cout << "Fat(2) = " << Fat(2) << endl;
		cout << "Fat(3) = " << Fat(3) << endl;
		cout << "Fib(0) = " << Fib(0) << endl;
		cout << "Fib(1) = " << Fib(1) << endl;
		cout << "Fib(2) = " << Fib(2) << endl;
		cout << "Fib(3) = " << Fib(3) << endl;
		
		cout << "Comparison cmp;" << endl;
		cout << "cmp << 1.0 < 2.0 < 3.0 > 2.5 : " << (bool)(cmp << 1.0 < 2.0 < 3.0 > 2.5) << endl;
		cout << "( cmp << 1.0 < 2.0 > 1.5 <= 2.5 >= 2.5 != 1.1 == 1.1 ? \"SIM\" : \"Nao\" ) : " <<
			( cmp << 1.0 < 2.0 > 1.5 <= 2.5 >= 2.5 != 1.1 == 1.1 ? "SIM" : "Nao" ) << endl;
		
		cout << endl << "---TestEnd---" << endl;
		
	};
	
};
